package br.ufu.lsi.database.engine;

import java.io.IOException;

import twitter4j.IDs;
import twitter4j.Logger;
import twitter4j.RateLimitStatus;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import br.ufu.lsi.database.factory.TwitterBuilder;

public class TwitterAccess {
    
    private static final Logger log = Logger.getLogger( TwitterAccess.class );
    
    private static final long SLEEP_TIME_IOEXCEPTION = 60 * 60 * 1000;
    
    private TwitterBuilder builder;
    
    private Twitter twitter;
    
    public TwitterAccess() {
        this.builder = new TwitterBuilder();
        this.twitter = builder.getTwitter();
    }
    
    
    public twitter4j.User getUserInfo( long userId ) throws Exception {

        try {

            twitter4j.User user = twitter.showUser( userId );
            
            return user;

        } catch ( TwitterException e ) {

            messageTwitterException( e );

            if ( e.getStatusCode() == 429 ) {

                handleTwitterException( e, "/friends/ids" );

                return getUserInfo( userId );

            } else if ( e.getCause() instanceof IOException ) {

                log.info( "Sleeping " + ( SLEEP_TIME_IOEXCEPTION / 1000 / 60 / 60 )
                        + "h due to connection error..." );

                Thread.sleep( SLEEP_TIME_IOEXCEPTION );

                return getUserInfo( userId );
            }
            
        } 
        return null;

    }

    /**
     * @param twitter
     * @param userId
     * @param cursor
     * @return
     * @throws Exception
     */
    public IDs getFriendsIDs( long userId, long cursor ) throws Exception {

        try {
            return twitter.getFriendsIDs( userId, cursor );
        } catch ( TwitterException e ) {

            messageTwitterException( e );
            if ( e.getStatusCode() == 429 ) {

                handleTwitterException( e, "/friends/ids" );

                return getFriendsIDs( userId, cursor );

            } else if ( e.getCause() instanceof IOException ) {

                log.info( "Sleeping " + ( SLEEP_TIME_IOEXCEPTION / 1000 / 60 / 60 )
                        + " due to connection error..." );

                Thread.sleep( SLEEP_TIME_IOEXCEPTION );

                return getFriendsIDs( userId, cursor );
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param twitter
     * @param userId
     * @param cursor
     * @return
     * @throws Exception
     */
    public IDs getFollowersIDs( long userId, long cursor ) throws Exception {

        try {
            return twitter.getFollowersIDs( userId, cursor );
        } catch ( TwitterException e ) {

            messageTwitterException( e );
            if ( e.getStatusCode() == 429 ) {

                handleTwitterException( e, "/followers/ids" );

                return getFollowersIDs( userId, cursor );

            } else if ( e.getCause() instanceof IOException ) {

                log.info( "Sleeping " + ( SLEEP_TIME_IOEXCEPTION / 1000 / 60 / 60 )
                        + " due to connection error..." );

                Thread.sleep( SLEEP_TIME_IOEXCEPTION );

                return getFollowersIDs( userId, cursor );
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }
        return null;
    }

    public void messageTwitterException( TwitterException e ) {

        if ( e.getErrorMessage() == null ) {
            log.error( e.getMessage() + " (" + e.getStatusCode() + ") " );
        } else {
            log.error( e.getErrorMessage() + " (" + e.getStatusCode() + ") " );
        }
    }

    public void handleTwitterException( TwitterException e, String keyStatus ) {

        RateLimitStatus status = e.getRateLimitStatus();
        try {

            if ( status != null && status.getSecondsUntilReset() > 0 ) {
                builder.updateTokens( twitter, keyStatus );
            }

        } catch ( TwitterException e1 ) {
            e1.printStackTrace();
        } catch ( InterruptedException e2 ) {
            e2.printStackTrace();
        }
    }
}
